package com.wu.xtkong.lock;

import java.util.Random;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;

import com.google.common.collect.Maps;

/** 
* @author 吴冬冬 
* @version 创建时间：2017年5月5日 下午4:06:19 
* 
*/
public class RedisLock implements Lock {
	@Autowired
    protected StringRedisTemplate redisTemplate;

    private static final Logger logger = Logger.getLogger(RedisLock.class);

    // lock flag stored in redis
    private static final String LOCKED = "TRUE";

    // timeout(ms)
    private static final long TIME_OUT = 30000;

    // lock expire time(s)
    public static final int EXPIRE = 60;

    // private Jedis jedis;
    private String key;

    // state flag
    private volatile boolean locked = false;

    private static ConcurrentMap<String, RedisLock> map = Maps.newConcurrentMap();

    public RedisLock(String key) {
        this.key = key;
        //redisTemplate = (StringRedisTemplate) ApplicationContextHolder.getBean("redisTemplate");
    }

    public static RedisLock getInstance(String key) {
    	RedisLock redisLock = map.get(key);
    	return redisLock != null ? redisLock : new RedisLock(key);
    }

    public boolean lock(long timeout) {
        long nano = System.nanoTime();
        timeout *= 1000000;
        final Random r = new Random();
        try {
        	//在timeout的时间范围内不断轮询锁
            while ((System.nanoTime() - nano) < timeout) {
            	//锁不存在的话，设置锁并设置锁过期时间，即加锁
                if (redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), LOCKED.getBytes())) {
                	//设置锁过期时间是为了在没有释放
                	redisTemplate.expire(key, EXPIRE, TimeUnit.SECONDS);
                	//锁的情况下锁过期后消失，不会造成永久阻塞
                    locked = true;
                    logger.debug("add RedisLock[" + key + "].");
                    break;
                }
                Thread.sleep(3, r.nextInt(500)); 
            }
            return true;
        } catch (Exception e) {
        	logger.error("key值为："+key+"获取锁失败");
        	logger.error("获取锁失败："+e.getMessage());
        	return false;
        }
    }

    @Override
    public void unlock() {
        if (locked) {
            logger.debug("release RedisLock[" + key + "].");
            redisTemplate.delete(key);
            locked = false;
        }
    }

    @Override
    public void lock() {
    	lock(TIME_OUT);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public Condition newCondition() {
        return null;
    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }
}
